#pragma once
#include <iostream>
#include <sys/epoll.h>
#include "Log.hpp"
#include "Common.hpp"

using namespace log_ns;

class Multiplex {
public:
    virtual bool AddEvents(int fd, struct epoll_event* event) = 0;
    virtual bool ModEvents(int fd, struct epoll_event* event) = 0;
    virtual bool DelEvents(int fd, struct epoll_event* event) = 0;
    virtual struct epoll_event* ReadyEvents() = 0;
    virtual int Wait(int timeout) = 0;
};

class Epoller : public Multiplex {
private:
    static const int gsize = 128;
    static const int gnum = 128;

    bool HandlerModEvents(int fd, int op, struct epoll_event* event) {
        int n = epoll_ctl(_epfd, op, fd, event);
        if (event == nullptr) {
            if (n < 0) {
                LOG(FATAL, "epoll delete ctl error, the reason is %s, fd: %d\n", strerror(errno), fd);
                return false;
            }
            LOG(INFO, "epoll tcl delete success, fd: %d\n", fd);
            return true;
        }

        if (n < 0) {
            LOG(FATAL, "epoll ctl %s error, the reason is %s, fd: %d\n", EventStr(event->events).c_str(), strerror(errno), fd);
            return false;
        }
        LOG(INFO, "epoll tcl %s success, fd: %d\n", EventStr(event->events).c_str(), fd);
        return true;
    }
public:
    Epoller() {
        _epfd = epoll_create(gsize);
        if (_epfd < 0) {
            LOG(FATAL, "epoll create error\n");
            exit(EPOLL_CREATE_ERROR);
        }
        LOG(INFO, "create epoll success, epfd: %d\n", _epfd);
    }

    std::string EventStr(uint32_t ev) {
        // if (rev == EPOLLOUT) return "EPOLLOUT";
        // else if (rev == EPOLLIN) return "EPOLLIN";
        // else return "EPOLLIN | EPOLLOUT";
        std::string evstr;
        if (ev & EPOLLIN) evstr += "EPOLLIN";
        if (ev & EPOLLOUT) evstr += " | EPOLLOUT";
        if (ev & EPOLLET) evstr += " | EPOLLET";
        return evstr;
    }

    bool AddEvents(int fd, struct epoll_event* event) override {
        return HandlerModEvents(fd, EPOLL_CTL_ADD, event);
    }

    bool DelEvents(int fd, struct epoll_event* event) override {

        return HandlerModEvents(fd, EPOLL_CTL_DEL, event);
    }

    bool ModEvents(int fd, struct epoll_event* event) override {
        return HandlerModEvents(fd, EPOLL_CTL_MOD, event);
    }

    int Wait(int timeout) override {
        int n = epoll_wait(_epfd, _events, gnum, timeout);
        return n;
    }

    struct epoll_event* ReadyEvents() override {
        return _events;
    }

    ~Epoller() {
        if (_epfd > 0) close(_epfd);
    }
private:
    int _epfd;
    struct epoll_event _events[gnum];
};